#include "../include/Light.h"
#include "../include/Scene.h"

Light::Light()
{
    //ctor
}

/**
* Constructeur d'un lumière
* @param position position de la lumière
* @return un lumière
*/
Light::Light(pVect position)
{
    this->position = position;
}

/**
* Constructeur d'une lumière
* @param position position de la lumière
* @param couleur couleur de la lumière
* @param puissance puissance émise par la lumière
* @return une lumière
*/
Light::Light(pVect position, Color couleur, float puissance)
{
    this->position = position;
    this->couleur = couleur;
    this->puissance = puissance;
}

Light::~Light()
{
    //dtor
}

/**
* Methode testant si un point voit un rayon lumineux
* @param hp point à tester
* @param origineLumiere point d'origine du rayon lumineux
* @param scene la scene
* @return vrai si le HP est visible depuis OrigineLumiere
*/
bool Light::ombrePoint(HitPoint * hp, pVect origineLumiere,Scene * scene){
    //vecteur point d'origine du rayon lumineux (peut etre différent de l'origine de la lumière) -> point d'impact
    pVect vLumHP = hp->position - origineLumiere;
    vLumHP.normalize();
    HitPoint* result = 0;
    HitPoint* buff;

    //Pour chaque objets de la scene
    std::list<Object*>::iterator it;
    for(it = scene->listObject.begin() ; it != scene->listObject.end() ; it++){
        //on vérifie si l'objet est intersecté par le rayon lumineux
        buff=(*it)->intersect(origineLumiere,vLumHP);

        if(buff!=0){
            if(result==0 || result->distance > buff->distance){
                if(result != 0) delete result;
                result = buff;
            } else {
                delete buff;
            }
        }
    }

    //si le rayon rencontre un autre objet que la cible
    if(result != 0){
        //on cherche a savoir si l'objet vu par la lumière est le meme objet que celui vu par la caméra et au meme point
        float dist = (hp->position - result->position).norm();
        //on ne garde que les cas où les 2 points d'intersection sont proches
        if(dist < 0.01){
            //on s'assure qu'il s'agit bien du meme objet
            if(result->objectTouched == hp->objectTouched){
                delete result;
                return true;        //il n'y a pas d'ombjet qui fait bariere à la lumière
            }
        }
        delete result;
        return false; //l'objet est a l'ombre
    }
    delete result;
    return true; //l'objet est éclairé
}

/**
* Méthode renvoyant la puissance lumineuse reçue par un point
* @param hp Point d'intersection a tester
* @param scene la scene
* @return puissance lumineuse
*/
float Light::getPuissanceAtPoint(HitPoint * hp, Scene * scene){
    //vecteur point d'intersection -> lumière ponctuelle
    pVect vObjLum = this->position - hp->position;
    vObjLum.normalize();
    //calcul du cosinus de l'angle entre le rayon lumieux et la normale de l'objet
    //calcul de l'intensité de l'action de la lumière sur le point d'intersection
    float scal = vObjLum * hp->normale;
    if(scal<0) scal = -scal;

    //si l'objet n'est PAS à l'ombre il recoit de la puissance lumineuse
    if(this->ombrePoint(hp,this->position,scene)){
        return puissance*scal;
    }
    return 0;

}
